#ifndef MQSERVER_MQ_HOST_HPP_
#define MQSERVER_MQ_HOST_HPP_
#include "mq_exchange.hpp"
#include "mq_queue.hpp"
#include "mq_binding.hpp"
#include "mq_message.hpp"
#include <memory>
#include <string>

namespace mqserver 
{
class VirtualHost;
using VirtualHostPtr = std::shared_ptr<VirtualHost>;

class VirtualHost
{
public:
    VirtualHost(const std::string& hname, const std::string& basedir, const std::string& dbfile)
        : host_name_(hname)
        , exchange_(std::make_shared<ExchangeManager>(dbfile))
        , msgqueue_(std::make_shared<MsgQueueManager>(dbfile))
        , binding_(std::make_shared<BindingManager>(dbfile))
        , message_(std::make_shared<MessageManager>(basedir)) 
    {
        // 获取所有队列信息, 恢复队列内的历史消息
        MsgQueuePtrMap mq_map = msgqueue_->getAllQueues();
        for(auto& [name, mq] : mq_map) 
            message_->initMessageQueue(name);
    }

    bool declareExchange(const std::string& name,       // 不存在则创建
            proto::message::ExchangeType type, 
            bool durable, bool auto_delete, 
            const google::protobuf::Map<std::string, std::string>& args)
    {
        return exchange_->declareExchange(name, type, durable, auto_delete, args);
    }
    void deleteExchange(const std::string& name) 
    {
        // 删除交换机的同时, 删除交换机相关的绑定信息。
        binding_->removeExchangeBindings(name);
        exchange_->deleteExchange(name);
    }
    bool existsExchange(const std::string& ename)
    {
        return exchange_->exists(ename);
    }
    ExchangePtr selectExchange(const std::string& ename)
    {
        return exchange_->selectExchange(ename);
    }

    bool declareQueue(const std::string name, bool durable, 
            bool exclusive, bool auto_delete,
            const google::protobuf::Map<std::string, std::string>& args_)
    {
        // 先初始化队列(消息存储的管理)
        message_->initMessageQueue(name);
        return msgqueue_->declareQueue(name, durable, exclusive, auto_delete, args_);
    }
    void deleteQueue(const std::string& name)
    {
        // 先删除队列的消息数据、相关绑定信息
        message_->destoryMessageQueue(name);
        binding_->removeMsgQueueBindings(name);
        msgqueue_->deleteQueue(name);
    }
    bool existsQueue(const std::string& qname)
    {
        return msgqueue_->exists(qname);
    }
    MsgQueuePtrMap getAllQueues()
    {
        return msgqueue_->getAllQueues();
    }

    bool bind(const std::string& ename, const std::string& qname, const std::string& binding_key)
    {
        ExchangePtr exch = exchange_->selectExchange(ename);
        if(exch.get() == nullptr)
        {
            LOG_ERROR << "exchange bind fail, the \"" << ename << "\" doesn't exists.\n";
            return false;
        }
        MsgQueuePtr mq = msgqueue_->selectQueue(qname);
        if(mq.get() == nullptr)
        {
            LOG_ERROR << "queue bind fail, the \"" << qname << "\" doesn't exists.\n";
            return false;
        }
        return binding_->bind(ename, qname, binding_key, exch->durable_ && mq->durable_);
    }
    void unbind(const std::string &ename, const std::string &qname)
    {
        binding_->unbind(ename, qname);
    }
    MsgQueueBindingMap getExchangeBindings(const std::string &ename)   
    {
        return binding_->getExchangeBindings(ename);
    }
    bool existsBinding(const std::string& ename, const std::string& qname)
    {
        return binding_->exists(ename, qname);
    }
    // 将消息发布到指定队列
    bool basicPublish(const std::string& qname, proto::message::BasicProperties* basic_props, const std::string& body)
    {
        MsgQueuePtr mq = msgqueue_->selectQueue(qname);
        if(mq.get() == nullptr)
        {
            LOG_ERROR << "queue bind fail, the \"" << qname << "\" doesn't exists.\n";
            return false;
        }
        return message_->insert(qname, basic_props, body, mq->durable_);
    }
    MessagePtr basicConsume(const std::string& qname)
    {
        return message_->front(qname);
    }
    bool basicAck(const std::string& qname, const std::string &msg_id)
    {
        return message_->ack(qname, msg_id);
    }
    void clear()
    {
        exchange_->clear();
        msgqueue_->clear();
        binding_->clear();
        message_->clear();
    }
private:
    std::string host_name_;
    ExchangeManagerPtr exchange_;
    MsgQueueManagerPtr msgqueue_;
    BindingManagerPtr binding_;
    MessageManagerPtr message_;
};

}

#endif